package com.cqrt.aop;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.fastjson.JSONObject;
import com.cqrt.constant.RTErrorCodeEnum;
import com.cqrt.constant.RTPlmConstant;
import com.cqrt.entity.RTPlanJobLinkDO;
import com.cqrt.entity.RTTemplateAttrLinkDO;
import com.cqrt.entity.RTTraverseParentDO;
import com.cqrt.mapper.RTProjectMapper;
import com.cqrt.mapper.RTProjectsTemplateMapper;
import com.cqrt.mapper.TraverseParentMapper;
import com.cqrt.service.RTProjectTemplateService;
import com.cqrt.util.TreeProcessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hustcad.plm.basic.util.TyplmEntityBaseUtil;
import com.hustcad.plm.pdm.core.util.Tools;
import com.hustcad.plm.rpm.model.dto.admin.TyppmProjectDTO;
import com.hustcad.plm.rpm.model.dto.team.ProjectTeamTreeDTO;
import com.hustcad.plm.rpm.model.dto.team.TyppmTeamTreeDTO;
import com.hustcad.plm.rpm.model.entity.admin.TyppmProjectTemplate;
import com.hustcad.plm.rpm.service.plan.TyppmPlanActiveService;
import com.hustcad.plm.rpm.service.team.TyppmProjectTeamService;
import com.ty.basic.entity.org.UserDO;
import com.ty.basic.service.snow.SnowflakeIdComponent;
import com.ty.basic.session.TyAccountContext;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigInteger;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;


@Aspect
@Component
@Slf4j
@Transactional
public class TemplateAop {

    @Resource
    private RTProjectsTemplateMapper rtProjectsTemplateMapper;
    @Resource
    private TyppmPlanActiveService planActiveService;
    @Resource
    private TraverseParentMapper traverseParentMapper;
    @Resource
    private SnowflakeIdComponent snowflakeIdComponent;
    @Resource
    private ObjectMapper objectMapper;
    @Resource
    private RTProjectTemplateService rtProjectTemplateService;
    @Resource
    private RTProjectMapper rtProjectMapper;

    @Around("execution(* com.hustcad.plm.rpm.template.service.TyppmProjectTemplateService.insertProjectTemplate(..))")
    public Object aroundControllerMethods(ProceedingJoinPoint joinPoint) throws Throwable {
        TyppmProjectDTO typpmProjectDTO = (TyppmProjectDTO) joinPoint.getArgs()[0];
        TyppmProjectTemplate typpmProjectTemplate = (TyppmProjectTemplate) joinPoint.proceed();
        String templateOid = typpmProjectTemplate.getOid();
        List<RTTemplateAttrLinkDO> templateAttrLinkDos = new ArrayList<>();
        log.info("==================开始生成模板状态属性=============>>>>");
        templateAttrLinkDos.add(createRTTemplateAttrLinkDo(Tools.toBigInteger(templateOid), RTPlmConstant.PUSH_MODE,
                                                           typpmProjectDTO.getPushMode()));
        templateAttrLinkDos.add(
                createRTTemplateAttrLinkDo(Tools.toBigInteger(templateOid), RTPlmConstant.DEVELOPMENT_LEVEL,
                                           typpmProjectDTO.getDevelopmentLevel()));
        templateAttrLinkDos.add(
                createRTTemplateAttrLinkDo(Tools.toBigInteger(templateOid), RTPlmConstant.DEVELOPMENT_MODE,
                                           typpmProjectDTO.getDevelopmentMode()));
        rtProjectsTemplateMapper.batchInsert(templateAttrLinkDos);
        typpmProjectTemplate.setPushMode(typpmProjectDTO.getPushMode());
        typpmProjectTemplate.setDevelopmentLevel(typpmProjectDTO.getDevelopmentLevel());
        typpmProjectTemplate.setDevelopmentMode(typpmProjectDTO.getDevelopmentMode());
        BigInteger projectId = rtProjectsTemplateMapper.selectProjectById(templateOid);
        log.info("==================开始修改模板状态=============>>>>");
        rtProjectTemplateService.updateTemplateStatus(projectId.toString(), RTPlmConstant.ZERO);
        return typpmProjectTemplate;
    }

    private RTTemplateAttrLinkDO createRTTemplateAttrLinkDo(BigInteger templateOid, String internalName, String value) {
        RTTemplateAttrLinkDO templateAttrLinkDo = new RTTemplateAttrLinkDO();
        templateAttrLinkDo.setOid(snowflakeIdComponent.getInstance().nextId());
        TyplmEntityBaseUtil.fillCommonFieldForCreate(templateAttrLinkDo);
        templateAttrLinkDo.setInternalName(internalName);
        templateAttrLinkDo.setValue(value);
        templateAttrLinkDo.setTemplateId(templateOid);
        return templateAttrLinkDo;
    }


    @Around("execution(* com.hustcad.plm.rpm.template.service.TyppmProjectTemplateService.updateProjectTemplate(..))")
    public Object updateProjectTemplate(ProceedingJoinPoint joinPoint) throws Throwable {
        TyppmProjectDTO projectDTO = (TyppmProjectDTO) joinPoint.getArgs()[0];
        BigInteger oid = rtProjectsTemplateMapper.selectTemplateIdByOid(projectDTO.getOid());
        TyppmProjectDTO dto = (TyppmProjectDTO) joinPoint.proceed();
        log.info("==================开始修改模板状态属性=============>>>>");
        rtProjectsTemplateMapper.batchDeleteWithLink(oid);
        List<RTTemplateAttrLinkDO> templateAttrLinkDos = new ArrayList<>();
        templateAttrLinkDos.add(createRTTemplateAttrLinkDo(oid, RTPlmConstant.PUSH_MODE, projectDTO.getPushMode()));
        templateAttrLinkDos.add(
                createRTTemplateAttrLinkDo(oid, RTPlmConstant.DEVELOPMENT_LEVEL, projectDTO.getDevelopmentLevel()));
        templateAttrLinkDos.add(
                createRTTemplateAttrLinkDo(oid, RTPlmConstant.DEVELOPMENT_MODE, projectDTO.getDevelopmentMode()));
        rtProjectsTemplateMapper.batchInsert(templateAttrLinkDos);
        return dto;
    }


    @Around("execution(* com.hustcad.plm.rpm.project.service.TyppmProjectService.getProjectDTOByOID(..))")
    public Object aroundGetProjectDTOByOID(ProceedingJoinPoint joinPoint) throws Throwable {
        String oid = (String) joinPoint.getArgs()[0];
        TyppmProjectDTO dto = (TyppmProjectDTO) joinPoint.proceed();
        TyppmProjectDTO typpmProjectDTO = rtProjectsTemplateMapper.queryTemplateAttrById(oid);
        if (ObjectUtil.isNotEmpty(typpmProjectDTO)) {
            dto.setPushMode(typpmProjectDTO.getPushMode());
            dto.setDevelopmentLevel(typpmProjectDTO.getDevelopmentLevel());
            dto.setDevelopmentMode(typpmProjectDTO.getDevelopmentMode());
        }
        return dto;
    }


    @Before("execution(* com.hustcad.plm.rpm.project.service.TyppmProjectService.getPrjStakeholderListByProject(..))")
    public void getTemplateLinkJob(JoinPoint joinPoint) {
        String oid = (String) joinPoint.getArgs()[0];
        BigInteger planId = rtProjectsTemplateMapper.getPlanById(oid);
        if (planId == null) {
            return;
        }
        JSONObject jsonObject = this.planActiveService.queryPlanActiveTreeByRootOIDAndRootOTYPE(
                planId.toString(), RTPlmConstant.PLAN_TYPE, Boolean.FALSE);
        if (ObjectUtil.isEmpty(jsonObject)) {
            log.warn("查询计划活动树为空，planId={}", planId);
            return;
        }
        Map<String, String> planLinkMap = TreeProcessor.extractSourceActiveOidAndUid(jsonObject);
        if (MapUtil.isEmpty(planLinkMap)) {
            log.info("未提取到有效的 planLinkMap，可能没有关联的活动");
            return;
        }
        if (MapUtil.isNotEmpty(planLinkMap)) {
            List<RTPlanJobLinkDO> rtPlanJobLinkDOS = mapToEntityList(planLinkMap);
            if (CollUtil.isEmpty(rtPlanJobLinkDOS)) {
                log.info("转换后的实体列表为空");
                return;
            }
            // 关键优化：批量查询数据库中已存在的记录
            Set<String> existingKeys = batchQueryExistingKeys(rtPlanJobLinkDOS);
            // 过滤掉已存在的记录
            if (CollUtil.isNotEmpty(existingKeys)) {
                List<RTPlanJobLinkDO> toInsertList = rtPlanJobLinkDOS.stream()
                        .filter(link -> !existingKeys.contains(generateUniqueKey(link)))
                        .collect(Collectors.toList());
                if (!toInsertList.isEmpty()) {
                    rtProjectsTemplateMapper.batchInsertLink(rtPlanJobLinkDOS);
                }
            } else {
                rtProjectsTemplateMapper.batchInsertLink(rtPlanJobLinkDOS);
            }
        }
    }

    /**
     * 生成唯一键：PLANOID|JOBOID
     */
    private String generateUniqueKey(RTPlanJobLinkDO link) {
        return link.getPlanoid() + "|" + link.getJoboid();
    }

    /**
     * 批量查询数据库中已存在的记录
     */
    private Set<String> batchQueryExistingKeys(List<RTPlanJobLinkDO> linkList) {
        if (linkList.isEmpty())
            return Collections.emptySet();
        List<Map<String, BigInteger>> keyPairs = linkList.stream()
                .map(link -> {
                    Map<String, BigInteger> pair = new HashMap<>();
                    pair.put("planOid", link.getPlanoid());
                    pair.put("jobOid", link.getJoboid());
                    return pair;
                })
                .collect(Collectors.toList());
        return new HashSet<>(rtProjectsTemplateMapper.selectExistingKeys(keyPairs));
    }

    //获取项目模板计划树
    @Before("execution(* com.hustcad.plm.rpm.project.service.TyppmProjectService.queryProjectListByParams(..))")
    @SuppressWarnings("unchecked")
    public void getTemplateLinkJobTest(JoinPoint joinPoint) {

        Map<String, Object> params = (Map<String, Object>) joinPoint.getArgs()[0];

        if (null != params.get("oid")) {

            String oid = params.get("oid").toString();
            if (oid != null) {
                BigInteger planId = rtProjectsTemplateMapper.getPlanById(oid);
                String planidstr = String.valueOf(planId);
                JSONObject jsonObject = this.planActiveService.queryPlanActiveTreeByRootOIDAndRootOTYPE(planidstr,
                                                                                                        RTPlmConstant.PLAN_TYPE,
                                                                                                        Boolean.FALSE);
                Map<String, String> planLinkMap = TreeProcessor.extractSourceActiveOidAndUid(jsonObject);
                if (MapUtil.isNotEmpty(planLinkMap)) {

                    List<RTTraverseParentDO> traverseParentList = new ArrayList<>();

                    for (Map.Entry<String, String> entry : planLinkMap.entrySet()) {

                        if (CollUtil.isNotEmpty(
                                traverseParentMapper.queryTraverseParentByTemplatePlanId(entry.getKey()))) {
                            continue;
                        }

                        RTTraverseParentDO traverseParent = new RTTraverseParentDO();
                        traverseParent.setObjectId(oid);
                        traverseParent.setTemplatePlanId(entry.getKey());
                        traverseParent.setProjectPlanId(entry.getValue());
                        traverseParent.setPlanId(planidstr);
                        traverseParentList.add(traverseParent);
                    }

                    traverseParentMapper.insertTraverseParent(traverseParentList);
                }
            }
        }
    }

    private List<RTPlanJobLinkDO> mapToEntityList(Map<String, String> planLinkMap) {
        List<RTPlanJobLinkDO> rtPlanJobLinkDOS = new ArrayList<>();
        for (Map.Entry<String, String> entry : planLinkMap.entrySet()) {
            RTPlanJobLinkDO rtPlanJobLinkDO = new RTPlanJobLinkDO();
            rtPlanJobLinkDO.setOid(snowflakeIdComponent.getInstance().nextId());
            TyplmEntityBaseUtil.fillCommonFieldForCreate(rtPlanJobLinkDO);
            rtPlanJobLinkDO.setPlanoid(BigInteger.valueOf(Long.parseLong(entry.getKey())));
            rtPlanJobLinkDO.setJoboid(BigInteger.valueOf(Long.parseLong(entry.getValue())));
            rtPlanJobLinkDOS.add(rtPlanJobLinkDO);
        }
        return rtPlanJobLinkDOS;
    }

    @Before("execution(* com.hustcad.plm.rpm.template.service.impl.TyppmProjectTemplateServiceImpl.delete(java.lang.String))")
    public void afterDeleteTemplate(JoinPoint joinPoint) {
        String oId = (String) joinPoint.getArgs()[0];
        List<BigInteger> projectTemplateOidList = Stream.of(oId)
                .filter(StringUtils::isNotEmpty).map(BigInteger::new).collect(Collectors.toList());
        rtProjectsTemplateMapper.deleteTemplateById(projectTemplateOidList);
    }


    @Around("execution(* com.hustcad.plm.rpm.template.service.TyppmProjectTemplateService.queryProjectTemplateList(java.util.Map))")
    @SuppressWarnings("unchecked")
    public Object aroundGetChildrenByParent(ProceedingJoinPoint joinPoint) throws Throwable {
        List<TyppmProjectTemplate> projectTemplates = (List<TyppmProjectTemplate>) joinPoint.proceed();
        if (CollUtil.isEmpty(projectTemplates)) {
            return projectTemplates;
        }
        List<String> OIDs = projectTemplates.stream()
                .map(TyppmProjectTemplate::getOid)
                .filter(ObjectUtil::isNotEmpty)
                .distinct()
                .collect(Collectors.toList());
        if (CollUtil.isNotEmpty(OIDs)) {
            // 4.1 批量获取补充属性
            Map<String, TyppmProjectTemplate> templateMap = rtProjectsTemplateMapper.selectAttrByIds(OIDs)
                    .stream()
                    .collect(Collectors.toMap(TyppmProjectTemplate::getOid, Function.identity()));
            // 4.2 批量设置属性
            for (TyppmProjectTemplate projectTemplate : projectTemplates) {
                String oid = projectTemplate.getOid();
                if (ObjectUtil.isNotEmpty(oid)) {
                    TyppmProjectTemplate attrTemplate = templateMap.get(oid);
                    if (ObjectUtil.isNotNull(attrTemplate)) {
                        projectTemplate.setDevelopmentMode(attrTemplate.getDevelopmentMode());
                        projectTemplate.setDevelopmentLevel(attrTemplate.getDevelopmentLevel());
                        projectTemplate.setPushMode(attrTemplate.getPushMode());
                    } else {
                        log.info("ProjectTemplate attributes not found for oid: {}", oid);
                    }
                }
            }
        }
        return projectTemplates;
    }


    @Around("execution(* com.hustcad.plm.rpm.project.service.TyppmProjectService.queryProjectListByParams(java.util.Map))")
    @SuppressWarnings("unchecked")
    public Object beforeFillData(ProceedingJoinPoint joinPoint) throws Throwable {

        Map<String, Object> params = (Map<String, Object>) joinPoint.getArgs()[0];
        String projectOID = (String) params.get("projectOID");
        TyppmProjectDTO project = rtProjectsTemplateMapper.selectTempAttr(projectOID);
        List<TyppmProjectDTO> typpmProjectDTOList = (List<TyppmProjectDTO>) joinPoint.proceed();
        TyppmProjectDTO typpmProjectDTO = typpmProjectDTOList.get(0);
        if (ObjectUtil.isNotNull(project)) {
            typpmProjectDTO.setDevelopmentLevel(project.getDevelopmentLevel());
            typpmProjectDTO.setPushMode(project.getPushMode());
            typpmProjectDTO.setDevelopmentMode(project.getDevelopmentMode());
        }

        return Collections.singletonList(typpmProjectDTO);
    }

    @Resource
    private TyppmProjectTeamService typpmProjectTeamService;

    //
    // 项目团队成员添加角色前，检测当前用户是否是项目团队角色里的组长
    @Around("execution(* com.hustcad.plm.rpm.service.team.TyppmProjectTeamService.insertRoleAndUserByContainerJAC(..))")
    public Object groupCheck(ProceedingJoinPoint joinPoint) throws Throwable {

        Object[] args = joinPoint.getArgs();
        String projectId = (String) args[0];
        String projectType = (String) args[1];
        TyppmTeamTreeDTO teamTreeDTO = (TyppmTeamTreeDTO) args[2];
        if ("参考创建".equals(teamTreeDTO.getChildName())) {
            return joinPoint.proceed();
        }
        // 判断是否已经存在计划模板
        List<BigInteger> plan = rtProjectMapper.selectplanTemplate(projectId);
        if (CollUtil.isNotEmpty(plan)) {
            if (plan.get(0).equals(BigInteger.valueOf(2)) || plan.get(0).equals(BigInteger.valueOf(4))) {
                List<ProjectTeamTreeDTO> projectTeamTreeDTOS = this.typpmProjectTeamService.queryContainerTeamByContainer(
                        projectId, projectType);
                UserDO user = TyAccountContext.getUser();
                // 检查当前用户是否为项目经理
                boolean isProjectManager = projectTeamTreeDTOS.stream()
                        .filter(item -> "PROJECT MANAGER".equals(item.getType()) || "PROJECT DIRECTOR".equals(
                                item.getType()))
                        .flatMap(dto -> Optional.ofNullable(dto.getChildren()).orElse(Collections.emptyList()).stream())
                        .map(TyppmTeamTreeDTO::getOid)
                        .anyMatch(oid -> String.valueOf(user.getOid()).equals(oid));

                boolean isGroupLeader = false;
                for (TyppmTeamTreeDTO typpmTeamTreeDTO : projectTeamTreeDTOS) {
                    if ("PROJECT MANAGER".equals(typpmTeamTreeDTO.getType()) || "PROJECT DIRECTOR".equals(
                            typpmTeamTreeDTO.getType())) {
                        List<TyppmTeamTreeDTO> children = Optional.ofNullable(typpmTeamTreeDTO.getChildren()).orElse(
                                Collections.emptyList());
                        if (CollUtil.isNotEmpty(children)) {
                            isGroupLeader = children.stream()
                                    .map(TyppmTeamTreeDTO::getOid)
                                    .anyMatch(oid -> String.valueOf(user.getOid()).equals(oid));
                            if (isGroupLeader) {
                                break;
                            }
                        }
                    }
                }
                if (!isGroupLeader) {
                    throw RTErrorCodeEnum.UPDATE_PROJECT_MEMBER_ERROR.getException(
                            "当前用户不是项目项目经理，无法维护组长");
                }
                if (!isProjectManager) {
                    throw RTErrorCodeEnum.UPDATE_PROJECT_MEMBER_ERROR.getException(
                            "当前用户不是项目项目经理，无法维护组长");
                }

                return joinPoint.proceed();
            }
        }
        List<ProjectTeamTreeDTO> projectTeamTreeDTOS = this.typpmProjectTeamService.queryContainerTeamByContainer(
                projectId, projectType);
        UserDO user = TyAccountContext.getUser();

        // 检查当前用户是否为项目经理
        boolean isProjectManager = projectTeamTreeDTOS.stream()
                .filter(item -> "PROJECT DIRECTOR".equals(item.getType()))
                .flatMap(dto -> Optional.ofNullable(dto.getChildren()).orElse(Collections.emptyList()).stream())
                .map(TyppmTeamTreeDTO::getOid)
                .anyMatch(oid -> String.valueOf(user.getOid()).equals(oid));

        if (!isProjectManager) {
            throw RTErrorCodeEnum.UPDATE_PROJECT_MEMBER_ERROR.getException("当前用户不是项目项目经理，无法维护组长");
        }
return joinPoint.proceed();
    }
}
